# encoding: utf-8

""" 此项目用于普通微博水军的分析

    微博水军是一群不可忽视的微博用户群体，
借助微博这个具有巨大影响力的社交平台，微博顺军在广告、
营销、热搜以及某些明星的绯闻事件等发挥着影响力，背后
操纵水军的公司、群体和个人也借此盈利，
    本项目，通过公开渠道获得的微博数据，先通过手工特征
使用无监督的级联聚类方法从大量无标签数据中筛选出水军群
体(可能含有少量非水军用户)，然后把筛选出的数据作为有标
签的训练样本，通过逻辑回归等有监督训练方法得到更高精准
度的判断模型。
"""


import argparse
import sys
import os
import pandas as pd
from utils.urlrequest import get_db
from model.cluster import (
    train,
    predict
)
from db.prepare import (
    get_tx_data,
    get_tx_data_and_output
)
from db.prepare2 import(
    mix_train_data_and_output,
    calc_one_data
)
from utils.load_data import(
    load_data,
    split_dataset
)
from settings import (
    clustring_rsl_sav_path,
    clustring_predict_sav_path
)


svm_xlst = ['tweets', 'n_fans', 'n_follows', 'fan_increate_rate', 'follow_increase_rate','tweet_increase_rate', 'follow_fan_ratio', 'v_sunshine', 'label_repeats', 'time_repeats', 'at_ratio']
svm_ylst = ['label']
navy_mapping = {0: '正常用户', 1: '水军一枚'}

parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, usage='用户无监督聚类水军,同时使用有监督学习方法分类水军的工具')

parser.add_argument('-d', '--dd-url', type=str, help='下载数据库的url地址', dest='url')

parser.add_argument('-c', '--clustering', action='store_true', help='运行聚类器', dest='clustering')

parser.add_argument('-ct', '--clustering-test', action='store_true', help='运行聚类器, 保存聚类器的参数', dest='clusteringAndTest')

parser.add_argument('-t', '--train-data', type=str, default='',
    help='传入本地数据库本地路径, 当不执行"-d -c"组合命令时, 运行聚类或者分类器均使用本参数传入本地数据路径', dest='train_data_path')
    
parser.add_argument('-s', '--svm', action='store_true', help='运行svm分类器, 组合命令"-s -t"训练svm分类器', dest='svming')

parser.add_argument('-se', '--svm-test', action='store_true', help='测试svm分类器, 组合命令"-se -t"测试svm分类器', dest='svmtest')

parser.add_argument('-p', '--predict', action='store_true', help='预测数据, "-p -s"使用svm进行预测, "-p -c"使用cluster进行预测', dest='predict')

parser.add_argument('-rc', '--pre-data-cluster', action='store_true', help='预处理聚类数据集, 需要与-t参数联合使用, 传入本地原始数据集路径, 例如 "python app.py -rc -t dataset_path_in_local"', dest='pdc')

parser.add_argument('-rs', '--pre-data-svm', type=str, help='预处理svm的数据集, 必须聚类出相应的水军数据集文件, 参数格式"sourcefilepath::positivefilepath::ratioOfNegativeAndPositive",其中第三个参数是正负样本的比例参数, 可以是"float"格式或者是"正样本/负样本"的除法形式, 本参数已经传入数据集, 因此不需要和-t参数组合使用', dest='pds')

parser.add_argument('--split', type=str, help='分割数据库, 参数是数据集路径, 默认分割比例0.2, 本命令行不提供比例调节, 要调节请修改app.py代码', dest='split')

parser.add_argument('--label-navy', type=str, help='根据聚类文件和原数据集, 获取聚类出来的水军数据, 并转换为svm可用数据格式, 参数格式是"metaDataSetPath::navyDataSetPath::storePath', dest='label_navy')


if __name__=='__main__':
    args = parser.parse_args(sys.argv[1:])
    
    if args.url and args.clustering:   
        # 从网络上加载, 并聚类
        meta_data_path = get_db(args.url)
        train_data = get_tx_data(meta_data_path)
        rsl = train(train_data)
        rsl.to_csv(clustring_rsl_sav_path, index=None)
        print('聚类完成, 聚类结果输出到 %s' % clustring_rsl_sav_path)
        exit()

    if args.url and args.clusteringAndTest: 
        # 从网络加载元数据, 并聚类, 保存聚类参数
        meta_data_path = get_db(args.url)
        train_data = get_tx_data(meta_data_path)
        rsl = train(train_data, issave=True)
        rsl.to_csv(clustring_rsl_sav_path, index=None)
        print('聚类完成, 聚类结果输出到 %s' % clustring_rsl_sav_path)
        exit()

    elif args.url and args.pdc:     
        # 加载元数据到本地, 并进行预处理
        meta_data_path = get_db(args.url)
        get_tx_data_and_output(meta_data_path)
        exit()
    
    elif args.pdc and args.train_data_path:
        # 对本地数据进行聚类预处理
        get_tx_data_and_output(args.train_data_path)
        exit()

    elif args.pds:   
        # 预处理svm训练数据集   
        metasourcefile, positivefile, ratio = args.pds.split('::')
        ratio = eval(ratio)
        mix_train_data_and_output(metasourcefile, positivefile, ratio)
        exit()
    
    elif args.split:
        # 分割数据集为训练集和测试集
        split_dataset(args.split)
        exit()

    elif args.url:      
        # 仅从网络加载元数据到本地
        meta_data_path = get_db(args.url)
        print('下载完成, 下载数据到 %s' % meta_data_path)
        exit()

    elif args.svming and args.train_data_path and not args.predict:
        # 加载本地数据, 训练svm
        from model.svmachine import train
        data = load_data(args.train_data_path)
        data.drop('_id', axis=1, inplace=True)
        train(data, svm_xlst, svm_ylst)
        exit()
    
    elif args.svmtest and args.train_data_path:
        # 加载本地测试数据集，对训练好的svm进行测试
        from model.svmachine import test
        data = load_data(args.train_data_path)
        data.drop('_id', axis=1, inplace=True)
        test(data, svm_xlst, svm_ylst)
        exit()

    elif args.svming and args.train_data_path and args.predict:
        # 加载本地数据, 使用svm进行预测
        from model.svmachine import predict
        from db.prepare2 import calc_one_data
        raw = load_data(args.train_data_path, encoding='gbk')
        data = calc_one_data(raw)
        for i in range(data.shape[0]):
            user = data.iloc[i]
            uid = user['_id']
            label = predict(user[1:])
            print('根据预测结果, 用户 {} 是 {}'.format(int(uid), navy_mapping[label[0]]))
        exit()
    
    elif args.clustering and args.train_data_path and not args.predict:  
        # 加载本地元数据或预处理数据, 并聚类
        try:
            data = get_tx_data(args.train_data_path)
        except:
            data = pd.read_csv(args.train_data_path)
        rsl = train(data)
        rsl.to_csv(clustring_rsl_sav_path, index=None)
        print('完成, 聚类结果输出到 %s' % clustring_rsl_sav_path)
        exit()

    elif args.clusteringAndTest and args.train_data_path and not args.predict: 
        # 加载本地元数据或预处理数据, 并聚类, 保存参数
        try:
            data = get_tx_data(args.train_data_path)
        except:
            data = pd.read_csv(args.train_data_path)
        rsl = train(data, issave=True)
        rsl.to_csv(clustring_rsl_sav_path, index=None)
        print('完成, 聚类结果输出到 %s' % clustring_rsl_sav_path)
        exit()

    elif args.clustering and args.train_data_path and args.predict:  
        # 加载本地元数据或预处理数据, 并使用聚类网络模型进行预测 --> 尽量不做展示 
        try:
            data = get_tx_data(args.train_data_path)
        except:
            data = pd.read_csv(args.train_data_path)
        rsl = predict(data)
        rsl.to_csv(clustring_predict_sav_path, index=None)
        print('完成, 聚类预测结果输出到 %s' % clustring_predict_sav_path)
        exit()

    elif args.label_navy:
        from settings import cdir
        from db.prepare2 import label_navy_data
        meta, navy,store = args.label_navy.split('::')
        data = label_navy_data(meta, navy)
        path = os.path.join(cdir, store)
        data.to_csv(path, index=None)
        print('\a处理完毕, 数据集输出到 %s' % path)
    else:
        print('该功能尚未支持或者是错误选项.')

